import os;
import typing as tp;
import asyncio;
import sys;

def require_sudo():
    if os.getuid() != 0:
        raise Exception("this script requires root privileges to execute")

async def stream_pipe(src: tp.Optional[asyncio.StreamReader], dist:tp.TextIO):
    if src:
        while True: 
            line = await src.readline()
            if line == b"":
                break
            dist.write(line.decode())

async def capture_pipe(src: tp.Optional[asyncio.StreamReader]) -> str:
    result = "" 
    if src:
        while True: 
            line = await src.readline()
            if line == b"":
                break
            result = result + line.decode()
    return result

async def async_exec(cmd:str):
    process = await asyncio.subprocess.create_subprocess_exec(cmd,
        stdout=asyncio.subprocess.PIPE, 
        stderr=asyncio.subprocess.PIPE)

    await asyncio.gather(
        stream_pipe(process.stdout, sys.stdout),
        stream_pipe(process.stderr, sys.stderr)
    )

    return await process.wait()

async def async_shell(cmd:str):
    process = await asyncio.subprocess.create_subprocess_shell(cmd,
        stdout=asyncio.subprocess.PIPE, 
        stderr=asyncio.subprocess.PIPE)

    await asyncio.gather(
        stream_pipe(process.stdout, sys.stdout),
        stream_pipe(process.stderr, sys.stderr)
    )

    return await process.wait()

async def async_stdout(cmd:str):
    process = await asyncio.subprocess.create_subprocess_shell(cmd,
        stdout=asyncio.subprocess.PIPE, 
        stderr=asyncio.subprocess.PIPE)

    result, _ = await asyncio.gather(
        capture_pipe(process.stdout),
        stream_pipe(process.stderr, sys.stderr)
    )

    if not await process.wait() == 0:
        raise Exception(f"failed in command [{cmd}]")

    return result

